package com.xiran.srpingboottemplateself.filter;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiran.srpingboottemplateself.exception.UsernameOrPasswordNullException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * 处理用户登录认证的过滤器。
 * 拦截 POST /login 请求，从JSON请求体中提取用户名和密码，并进行认证。
 * 认证成功或失败后，由配置的 SuccessHandler 或 FailureHandler 返回JSON响应。
 * 这个过滤器取代了默认的 UsernamePasswordAuthenticationFilter。
 */
//MGZ TODO 2025/8/20: 删除了@bean
public class JwtLoginProcessingFilter extends AbstractAuthenticationProcessingFilter {

    private static final String LOGIN_URI = "/api/user/login";
    private static final String JSON_USERNAME_FIELD = "username";
    private static final String JSON_PASSWORD_FIELD = "password";

    private final ObjectMapper objectMapper;

    // 【核心修改】显式编写构造函数，并调用父类构造
    public JwtLoginProcessingFilter(ObjectMapper objectMapper) {
        super(new AntPathRequestMatcher(LOGIN_URI, "POST")); // 必须首先调用父类构造
        this.objectMapper = objectMapper;
    }

    /**
     * 尝试对请求进行认证。
     *
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     * @return 认证成功的Authentication对象
     * @throws AuthenticationException 如果认证失败
     * @throws IOException             如果读取请求体失败
     * @throws ServletException        如果发生Servlet错误
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {

        // 解析提交的 JSON 数据
        JsonNode requestBodyJson = objectMapper.readTree(request.getInputStream());
        JsonNode usernameNode = requestBodyJson.get(JSON_USERNAME_FIELD);
        JsonNode passwordNode = requestBodyJson.get(JSON_PASSWORD_FIELD);

        // 判断用户名、密码是否为空
        if (isNodeNullOrBlank(usernameNode) || isNodeNullOrBlank(passwordNode)) {
            throw new UsernameOrPasswordNullException("用户名或密码不能为空");
        }

        String username = usernameNode.textValue();
        String password = passwordNode.textValue();

        // 将用户名、密码封装到 Token 中（未认证的Token）
        UsernamePasswordAuthenticationToken authRequest =
                new UsernamePasswordAuthenticationToken(username, password);

        // 设置请求的详细信息，方便后续获取（如IP、Session等）
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));

        // 委托给 AuthenticationManager 进行认证
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    /**
     * 检查JsonNode是否为空或内容为空白
     * @param node JsonNode to check
     * @return true if null or blank, false otherwise
     */
    private boolean isNodeNullOrBlank(JsonNode node) {
        return Objects.isNull(node) || StringUtils.isBlank(node.textValue());
    }
}